package it.geosolutions.geoserver.rest.vgis;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Objects;
import java.util.zip.*;


/**
 * @author chenxw
 * @version 1.0
 * @date 2022/2/18 15:54
 */
public class ZipUtils {

    // 符号"/"用来作为目录标识判断符
    private static final String PATH = "/";
    private static final int BUFFER = 1024;

    //shp文件解压，返回shp文件路径
    public static String unShpZipAndGetShpPath(String zipFile, String destDir) throws IOException {
        String  shpFileName=null;
        ZipFile zip = null;
        try {

            zip = new ZipFile(zipFile, Charset.forName("GBK"));//解决中文文件夹乱码

            File pathFile = new File(destDir);
            if (!pathFile.exists()) {
                pathFile.mkdirs();
            }

            for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements();) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                String zipEntryName = entry.getName();
                if(zipEntryName.endsWith(".shp")) {
                    shpFileName = zipEntryName;
                }
                InputStream in = zip.getInputStream(entry);
                //路径替换
                String outPath = (destDir  +"/"+ zipEntryName).replaceAll("\\*", "/");
                // 判断路径是否存在,不存在则创建文件路径
                File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
                if (!file.exists()) {
                    file.mkdirs();
                }
                // 判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
                if (new File(outPath).isDirectory()) {
                    continue;
                }
                // 输出文件路径信息
                FileOutputStream out = new FileOutputStream(outPath);
                byte[] buf1 = new byte[1024];
                int len;
                while ((len = in.read(buf1)) > 0) {
                    out.write(buf1, 0, len);
                }
                in.close();
                out.close();

            }


        }
        catch (IOException ex)
        {
            System.out.println("unShpZip ex:"+ex);
        } finally {
            if (Objects.nonNull(zip)) {
                zip.close();
            }
        }
        return shpFileName;
    }



    //压缩文件解压到当前目录，并返回指定后缀的文件路径
    public static String unZipAndGetFileBySuffix(String zipFilePath, String  suffix) throws IOException {
        String  returnFileName=null;
        ZipFile zip = null;
        try {

//            String temp[]=zipFilePath.split(File.separator);
//            String zipFileName=temp[temp.length-1];
            File zipFileObj=new File(zipFilePath);
            String zipFileName=zipFileObj.getName();
            zipFileName=zipFileName.substring(0, zipFileName.lastIndexOf("."));;
            String zipFileDir=zipFileObj.getParent();
            zip = new ZipFile(zipFilePath, Charset.forName("GBK"));//解决中文文件夹乱码

            String destDir=zipFileDir+File.separator+zipFileName;
            File pathFile = new File(destDir);
            if (!pathFile.exists()) {
                pathFile.mkdirs();
            }

            for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements();) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                String zipEntryName = entry.getName();
                if(zipEntryName.endsWith(suffix)) {
                    returnFileName = destDir+File.separator+zipEntryName;
                }
                InputStream in = zip.getInputStream(entry);
                //路径替换
                String outPath = (destDir  +"/"+ zipEntryName).replaceAll("\\*", "/");
                // 判断路径是否存在,不存在则创建文件路径
                File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
                if (!file.exists()) {
                    file.mkdirs();
                }
                // 判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
                if (new File(outPath).isDirectory()) {
                    continue;
                }
                // 输出文件路径信息
                FileOutputStream out = new FileOutputStream(outPath);
                byte[] buf1 = new byte[1024];
                int len;
                while ((len = in.read(buf1)) > 0) {
                    out.write(buf1, 0, len);
                }
                in.close();
                out.close();

            }


        }
        catch (IOException ex)
        {
            System.out.println("unShpZip ex:"+ex);
        } finally {
            if (Objects.nonNull(zip)) {
                zip.close();
            }
        }
        return returnFileName;
    }


    //对压缩包里的所有文件进行重命名再打新的压缩包
    public static String  renameZipFile(String zipFilePath)throws IOException {
        String returnNewZipFile = null;
        ZipFile zip = null;
        try {
            File zipFileObj = new File(zipFilePath);
            String oldZipFileName = zipFileObj.getName();
            oldZipFileName = oldZipFileName.substring(0, oldZipFileName.lastIndexOf("."));
            String zipFileDir = zipFileObj.getParent();
            zip = new ZipFile(zipFilePath, Charset.forName("GBK"));//解决中文文件夹乱码

            String newZipFileName=FileUtils.getFileNameRemoveSubfixAddUUid(zipFileObj.getName());

            String destDir = zipFileDir + File.separator + newZipFileName;
            File pathFile = new File(destDir);
            if (!pathFile.exists()) {
                pathFile.mkdirs();
            }

            //将压缩包里的文件重命名后复制到新的文件夹
            for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements(); ) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                String zipEntryName = entry.getName();
                zipEntryName=zipEntryName.replace(oldZipFileName,newZipFileName);
                InputStream in = zip.getInputStream(entry);
                //路径替换
                String outPath = (destDir + "/" + zipEntryName).replaceAll("\\*", "/");
                // 判断路径是否存在,不存在则创建文件路径
                File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
                if (!file.exists()) {
                    file.mkdirs();
                }
                // 判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
                if (new File(outPath).isDirectory()) {
                    continue;
                }
                // 输出文件路径信息
                FileOutputStream out = new FileOutputStream(outPath);
                byte[] buf1 = new byte[1024];
                int len;
                while ((len = in.read(buf1)) > 0) {
                    out.write(buf1, 0, len);
                }
                in.close();
                out.close();

            }

            //对新的文件夹内的文件进行压缩
            File zipFile=directCompressionCompress(pathFile);
            returnNewZipFile=zipFile.getAbsolutePath();


        } catch (IOException ex) {
            System.out.println("renameZip ex:" + ex);
        }
        catch (Exception ex) {
            System.out.println("renameZip ex:" + ex);
        }
        finally {
            if (Objects.nonNull(zip)) {
                zip.close();
            }
        }
        return returnNewZipFile;
    }


    //直接压缩文件夹 里的文件
    public static File directCompressionCompress(File srcFile) throws Exception {

        String name = srcFile.getName();
        String path = srcFile.getParent() + File.separator + name + ".zip";
        File destFile = new File(path);
        // 对输出文件做CRC32校验
        CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(
                destFile), new CRC32());

        ZipOutputStream zos = new ZipOutputStream(cos);

        Collection<File> files = org.apache.commons.io.FileUtils.listFiles(srcFile, null, false);

        for (File file : files) {
            compress(file, zos, "");
        }
        zos.flush();
        zos.close();
        return destFile;
    }

    /**
     * 压缩
     *
     * @param srcFile
     *            源路径
     * @param zos
     *            ZipOutputStream
     * @param basePath
     *            压缩包内相对路径
     * @throws Exception
     */
    private  static void compress(File srcFile, ZipOutputStream zos,
                           String basePath) throws Exception {
        if (srcFile.isDirectory()) {
            compressDir(srcFile, zos, basePath);
        } else {
            compressFile(srcFile, zos, basePath);
        }
    }

    /**
     * 压缩目录
     *
     * @param dir
     * @param zos
     * @param basePath
     * @throws Exception
     */
    private static  void compressDir(File dir, ZipOutputStream zos,
                              String basePath) throws Exception {

        File[] files = dir.listFiles();

        // 构建空目录
        if (files.length < 1) {
            ZipEntry entry = new ZipEntry(basePath + dir.getName() + PATH);

            zos.putNextEntry(entry);
            zos.closeEntry();
        }

        for (File file : files) {

            // 递归压缩
            compress(file, zos, basePath + dir.getName() + PATH);

        }
    }

    /**
     * 文件压缩
     *
     * @param file
     *            待压缩文件
     * @param zos
     *            ZipOutputStream
     * @param dir
     *            压缩文件中的当前路径
     * @throws Exception
     */
    private static  void compressFile(File file, ZipOutputStream zos, String dir)
            throws Exception {

        /**
         * 压缩包内文件名定义
         *
         * <pre>
         * 如果有多级目录，那么这里就需要给出包含目录的文件名
         * 如果用WinRAR打开压缩包，中文名将显示为乱码
         * </pre>
         */
        ZipEntry entry = new ZipEntry(dir + file.getName());

        zos.putNextEntry(entry);

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
                file));

        int count;
        byte data[] = new byte[BUFFER];
        while ((count = bis.read(data, 0, BUFFER)) != -1) {
            zos.write(data, 0, count);
        }
        bis.close();

        zos.closeEntry();
    }

    //文件解压到指定目录，返回成功或失败
    public static boolean unZip(String zipFile, String destDir)
    {
        boolean  issucess=false;
        try {

            ZipFile zip = new ZipFile(zipFile, Charset.forName("GBK"));//解决中文文件夹乱码
            System.out.println(zip.getName());
            //String name = zip.getName().substring(zip.getName().lastIndexOf('\\')+1, zip.getName().length());

            File pathFile = new File(destDir);
            if (!pathFile.exists()) {
                pathFile.mkdirs();
            }

            for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements();) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                String zipEntryName = entry.getName();
                InputStream in = zip.getInputStream(entry);
                String outPath = (destDir  +"/"+ zipEntryName).replaceAll("\\*", "/");
                // 判断路径是否存在,不存在则创建文件路径
                File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
                if (!file.exists()) {
                    file.mkdirs();
                }
                // 判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
                if (new File(outPath).isDirectory()) {
                    continue;
                }
                // 输出文件路径信息
                System.out.println(outPath);

                FileOutputStream out = new FileOutputStream(outPath);
                byte[] buf1 = new byte[1024];
                int len;
                while ((len = in.read(buf1)) > 0) {
                    out.write(buf1, 0, len);
                }
                in.close();
                out.close();

            }
            System.out.println("******************解压完毕********************");
            issucess=true;

        }
        catch (IOException ex)
        {

        }
        return issucess;
    }

}
